﻿
namespace TingSLsocket

open System
open System.IO
open System.Net
open System.Net.Sockets
open System.Text
open System.Diagnostics
open SocketExtend
open ServerSocketExtend

[<Sealed>]
type PolicyServer(relativePath) =

    static let _LsnPort = 943
    static let _PolicyRequestString = "<policy-file-request/>"

    let _lsnSocket = NewTcpSocket()
    let _policyData = 
        let fullPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, relativePath)
        File.ReadAllBytes fullPath

    let handle clientSocket = async {
        // the stream owns the socket
        // close the stream will automatically close the socket
        use netstream = new NetworkStream(clientSocket,true)

        // ##################### receive request
        let recvBuffer = Array.zeroCreate<byte> _PolicyRequestString.Length
        let numRecved = ref 0
        while !numRecved < _PolicyRequestString.Length do
            let! oneRead = netstream.AsyncRead(recvBuffer,!numRecved,_PolicyRequestString.Length - !numRecved)
            numRecved := !numRecved + oneRead

        // ##################### send back policy
        let reqString = Encoding.ASCII.GetString(recvBuffer)
        if reqString.Equals(_PolicyRequestString,StringComparison.OrdinalIgnoreCase) then
            do! netstream.AsyncWrite(_policyData)
        else
            Trace.TraceWarning("invalid request string: '{0}'",reqString)
    }

    static member LsnPort = _LsnPort
    static member PolicyRequestString = _PolicyRequestString

    member this.Start() =
        _lsnSocket.Bind <| new IPEndPoint(IPAddress.Any,_LsnPort)
        _lsnSocket.Listen 10

        async {
            while true do
                let! clientSocket = _lsnSocket.AsyncAccept()
                clientSocket 
                |> handle
                |> Async.StartImmediate
        } 
        |> Async.StartImmediate

    member this.Dispose() =
        _lsnSocket.Close()

    interface IDisposable with
        member this.Dispose() = this.Dispose()
        

